package com.sky.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.ErrnumsConstant;
import com.sky.constant.MessageConstant;
import com.sky.constant.PasswordConstant;
import com.sky.constant.StatusConstant;
import com.sky.context.BaseContext;
import com.sky.dto.EmployeeDTO;
import com.sky.dto.EmployeeLoginDTO;
import com.sky.dto.EmployeePageQueryDTO;
import com.sky.entity.Employee;
import com.sky.exception.AccountLockedException;
import com.sky.exception.AccountNotFoundException;
import com.sky.exception.PasswordErrorException;
import com.sky.mapper.EmployeeMapper;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.EmployeeService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

@Service
public class EmployeeServiceImpl implements EmployeeService {

    @Autowired
    private EmployeeMapper employeeMapper;

    /**
     * 员工登录
     *
     * @param employeeLoginDTO
     * @return
     */
    public Employee login(EmployeeLoginDTO employeeLoginDTO) {
        String username = employeeLoginDTO.getUsername();
        String password = employeeLoginDTO.getPassword();

        //1、根据用户名查询数据库中的数据
        Employee employee = employeeMapper.getByUsername(username);

        //2、处理各种异常情况（用户名不存在、密码不对、账号被锁定）
        if (employee == null) {
            //账号不存在
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }

        if (employee.getStatus() == StatusConstant.DISABLE) {
            //账号被锁定
            throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
        }

        //进行密码验证

        //使用BCrypt加密 验证
        BCryptPasswordEncoder bCryptPasswordEncoder=new BCryptPasswordEncoder();
        boolean PasswordeEstimate=bCryptPasswordEncoder.matches(password,employee.getPassword());
        //密码比对
        if (!PasswordeEstimate) {
            int errnums=employee.getErrnums();
            errnums+=1;
            employeeMapper.setErrnums(errnums,employee.getId());
            //错误次数大于5
            if(errnums>ErrnumsConstant.DEAULT_ERRNUMS_FIVE){
                //设置异常状态码
                employeeMapper.setStatus(StatusConstant.DISABLE,employee.getId());
                //30分钟后用户错误次数于状态码恢复
                scheduleResetTask(employee.getId());
                throw new PasswordErrorException(MessageConstant.PASSWORD_ERRNUMS);
            }
            //密码错误
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }

        //3、返回实体对象
        return employee;
    }

    // 定时任务调度方法
    public void scheduleResetTask(long UserID) {
        Timer timer = new Timer();
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                timing(UserID);
            }
        };
        timer.schedule(task, 30 * 60 * 1000); // 30分钟后执行
    }

    //实际重置方法
    public void timing(long UserID) {
        // 30分钟后 将状态码和错误次数重置
        employeeMapper.setStatus(StatusConstant.ENABLE,UserID);
        employeeMapper.setErrnums(ErrnumsConstant.DEFAULT_ERRNUMS_ZERO,UserID);
    }

    /**
     * 添加员工
     * @param employeeDTO
     */
    @Override
    public void addMployee(EmployeeDTO employeeDTO) {
        Employee employee=new Employee();
        //将DTO的数据拷贝到原来的数据库类
        BeanUtils.copyProperties(employeeDTO,employee);

        //添加默认状态码 1
        employee.setStatus(StatusConstant.ENABLE);

        //使用BCrypt加密
        BCryptPasswordEncoder bCryptPasswordEncoder=new BCryptPasswordEncoder();
        //默认密码为123
        String newPassword=bCryptPasswordEncoder.encode(PasswordConstant.DEFAULT_PASSWORD);
        employee.setPassword(newPassword);

        //添加当前的创建时间和修改时间
//        employee.setCreateTime(LocalDateTime.now());
//        employee.setUpdateTime(LocalDateTime.now());

        //添加默认的错误次数
        employee.setErrnums(ErrnumsConstant.DEFAULT_ERRNUMS_ZERO);

        //把线程内的id取出
        employee.setCreateUser(BaseContext.getCurrentId());
        employee.setCreateUser(BaseContext.getCurrentId());
        //调用插入接口
        employeeMapper.insert(employee);
    }

    /**
     * 分页查询
     * @param employeePageQueryDTO
     * @return
     */
    @Override
    public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {
        //使用pageHelper 简化分页查询         参数1 当前查询的页数 参数2 每页多少条数据
        PageHelper.startPage(employeePageQueryDTO.getPage(),employeePageQueryDTO.getPageSize());

        //数据库接口
        //返回的类型Page是PageHelper内的
        /**
         *     <select id="getPage" resultType="com.sky.entity.Employee">
         *         select * from employee
         *         <where>
         *             <if test="name!=null and name!=''">
         *                 and name like concat('%',#{name},'%')
         *             </if>
         *         </where>
         *         order by create_time desc
         *     </select>
         *     这是SQL语句解释
         *     如果当name字段不为空时，说明要查询名字 就把下面那个模糊匹配加上 如果为空就不加
         *     以创建时间排序
         *     limit这种语句 PageHelper会自动帮我们加上 至于是几页，几条数据前端已经传过来，PageHelper会自动计算，并帮我们加上
         */
        Page<Employee> page=employeeMapper.getPage(employeePageQueryDTO);

        //共有多少条数据
        long total = page.getTotal();
        //查询出来每页的数据
        List<Employee> result = page.getResult();

        //返回对应的类型，并添加数据
        return new PageResult(total,result);
    }

    /**
     * 启用禁用用户状态
     * @param status
     * @param id
     */
    @Override
    public void statusModif(Integer status, Long id) {
        Employee employee= Employee.builder()
                .id(id)
                .status(status)
                .build();
        employeeMapper.updateData(employee);
    }

    /**
     * 根据id获取用户信息
     * @param id
     * @return
     */
    @Override
    public Employee getById(Long id) {
        Employee employee=employeeMapper.getById(id);
        //即使密码加密后 也不把加密的密码原文返回 修改为**
        employee.setPassword("****");
        return employee;
    }

    /**
     * 修改员工信息
     * @param employeeDTO
     */
    @Override
    public void updateEmployee(EmployeeDTO employeeDTO) {
        //因为数据库的类型是employee 所以要把DTO转成employee
        Employee employee=new Employee();
        BeanUtils.copyProperties(employeeDTO,employee);

        //设置修改时间和修改数据的用户id
//        employee.setUpdateTime(LocalDateTime.now());
//        employee.setUpdateUser(BaseContext.getCurrentId());

        employeeMapper.updateData(employee);
    }

}
